#pragma once

#include "stdafx.h"
#include "System.h"

#ifdef GTEST
#include <gtest/gtest.h>
#else
#define FRIEND_TEST(r1, r2)
#endif

#include <map>
#include <vector>

#pragma warning(disable:4251) // disable the warning: class 'std::set<_Kty>' needs to have dll-interface to be used by clients of class

class TXNMGR_API HeapMgr
{
public:
	void Dump();
	bool Clear();


	FRIEND_TEST(HeapMgr_TestCase, AllocStorage);
	FRIEND_TEST(HeapMgr_TestCase, FreeStorage);
	FRIEND_TEST(TxnMgr_TestCase, UndoWithTwoTxnMgr);
	FRIEND_TEST(TxnMgr_TestCase, AllocStorage);

	// Get the memory manager.
	// There should be only one instance.
	static		HeapMgr* Get();

	// Allocate memory for storing
	void*		AllocStorage(size_t nSize);

	// Deallocate memory of storage
	BOOL		FreeStorage(void* pAddress);

	// Exception filter
	// Backup the target page
	LONG		ExceptionFilter(PEXCEPTION_POINTERS pVEHExp);

	// Get one page's size
	size_t		GetPageSize() const;

	// Get page's address
	void*		GetPageAddress(void* pAddress) const;

	// Get memory information
	BOOL		GetStorage(void* pAddress, void** p = NULL, size_t* pnSize = NULL) const;

	// Is the memory controlled by this manager
	BOOL		IsStorage(void* pAddress) const;

	// Lock all storage memory
	BOOL		LockAll() const;

	// Unlock all storage memory
	BOOL		UnlockAll() const;

	// Whether the page is locked
	BOOL		IsLocked(void* pAddress) const;

	// Lock memory
	BOOL		LockStorage(void* pAddress, size_t nSize) const;

	// Unlock memory
	BOOL		UnlockStorage(void* pAddress, size_t nSize) const;

	// Backup a page memory
	// return the base address of the "to" memory
	void*		BackupAPage(void* pAddress);

private:
	// hide these 2 guys
	HeapMgr(void);
	~HeapMgr(void);

	// disable these 2 guys
	HeapMgr(const HeapMgr& lhs);
	HeapMgr& operator = (const HeapMgr& lhs);


private:
	// Pages that have been allocated
	std::vector<void*>	m_vPageAllocated;

	// Memory that has been used
	// _Kty: the address of the memory that has been used
	std::map<void*, size_t> m_mMemoryUsed;

	// Memory that has not been used
	// _Kty: the address of the memory that has been unused
	std::map<void*, size_t> m_mMemoryUnused;
};

